package com.mashangwan.paleto.security.auth.ajax;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mashangwan.paleto.common.web.View;
import com.mashangwan.paleto.domain.Role;
import com.mashangwan.paleto.domain.User;
import com.mashangwan.paleto.security.model.UserContext;
import com.mashangwan.paleto.security.model.token.JwtToken;
import com.mashangwan.paleto.security.model.token.JwtTokenFactory;
import com.mashangwan.paleto.service.RoleService;
import com.mashangwan.paleto.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * AjaxAwareAuthenticationSuccessHandler
 *
 * @author linfeng
 * @since 2017/7/30
 */
@Component
public class AjaxAwareAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    private final ObjectMapper mapper;
    private final JwtTokenFactory tokenFactory;

    @Autowired
    public AjaxAwareAuthenticationSuccessHandler(final ObjectMapper mapper, final JwtTokenFactory tokenFactory) {
        this.mapper = mapper;
        this.tokenFactory = tokenFactory;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {

        UserContext userContext = (UserContext) authentication.getPrincipal();

        User user = userService.findByLoginName(userContext.getUsername());
        if (user == null) {
            throw new UsernameNotFoundException("User not found: " + userContext.getUsername());
        }

        userContext.setUser(user);

        WebAuthenticationDetails wauth = (WebAuthenticationDetails) authentication.getDetails();
        userService.updateUserLoginInfo(wauth.getRemoteAddress(), user.getId());

//        request.getSession().setAttribute("", user);

        JwtToken accessToken = tokenFactory.createAccessJwtToken(userContext);
        JwtToken refreshToken = tokenFactory.createRefreshToken(userContext);

        Map<String, Object> tokenMap = new HashMap<String, Object>();
        tokenMap.put("token", accessToken.getToken());
        tokenMap.put("refreshToken", refreshToken.getToken());
        tokenMap.put("name", user.getName());
        tokenMap.put("avatar", user.getAvatar());
        tokenMap.put("username", user.getLoginDate());

        Set<String> allPermissions = new HashSet<>();
        List<Map<String, Object>> roleMapList = new ArrayList<>();
        Map<String, Object> roleMap;

        List<Role> roles = roleService.findRoles(user.getId());
        for (Role duties: roles) {
            roleMap = new HashMap<>();
            roleMap.put("id", duties.getId());
            roleMap.put("name", duties.getName());
            roleMapList.add(roleMap);
            allPermissions.add(duties.getEnname());

        }
        tokenMap.put("roles", roleMapList);
        tokenMap.put("permissions", allPermissions);
        tokenMap.put("roleId", userContext.getRole().getId());

        View<Map<String, Object>> view = new View<>(200, "OK");
        view.setData(tokenMap);

        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        mapper.writeValue(response.getWriter(), view);

        clearAuthenticationAttributes(request);
    }

    /**
     * Removes temporary authentication-related data which may have been stored
     * in the session during the authentication process..
     */
    protected final void clearAuthenticationAttributes(HttpServletRequest request) {
        HttpSession session = request.getSession(false);

        if (session == null) {
            return;
        }

        session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
    }
}
